/**
 * Copyright (c) Huawei Technologies Co., Ltd. 1987-2021. All rights reserved.
*/

package com.gitee.fufu669.aspect;

import com.gitee.fufu669.common.CacheKeyCommon;
import com.gitee.fufu669.config.exception.CacheServerErrorCode;
import com.gitee.fufu669.config.exception.CacheServerException;
import com.gitee.fufu669.service.CacheService;
import com.gitee.fufu669.utils.CacheAopUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.gitee.fufu669.utils.CacheRedisKeyUtil;

import java.lang.reflect.Method;

/**
 * @author wangfupeng on 2017-5-6.
 */
@Aspect
// 组件注解
@Component
// 注解
@SuppressWarnings("rawtypes")
/** @author wangfupeng */
/**
 * TODO
*/
public class LockWithCacheAop {

    /**
     * TODO
    */
    public static final Logger logger = LoggerFactory.getLogger(LockWithCacheAop.class);

    // 注解
    @Autowired
    // TODO
    private CacheService cacheService;

    // 注解
    @Around("@annotation(com.gitee.fufu669.aspect.LockWithCache)")
    /**
     * TODO
    */
    public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        /** 获取注解里面的value*/
        String methodName = null;
        // 赋值
        int expireSeconds = CacheKeyCommon.CACHESERVICE_REDIS_LOCK_DEFAULT_EXPIRED_SECONDS;
        // 赋值
        String description = "";
        // 尝试下面的代码
        try {
            // 字符串赋值
            String targetName = proceedingJoinPoint.getTarget().getClass().getName();
            // TODO
            methodName = proceedingJoinPoint.getSignature().getName();
            // TODO
            Class targetClass = Class.forName(targetName);
            // TODO
            Method[] methods = targetClass.getMethods();
            // 遍历
            for (Method method : methods) {
                // 判断
                if (method.getName().equals(methodName)) {
                    // TODO
                    expireSeconds = method.getAnnotation(LockWithCache.class).expireSeconds();
                    // TODO
                    description = method.getAnnotation(LockWithCache.class).description();
                    // 跳出
                    break;
                }
            }
        // 捕捉异常
        } catch (Exception e) {
            logger.info(e.toString());
        }
        /** 拦截的方法参数名*/
        Signature signature = proceedingJoinPoint.getSignature();
        // TODO
        MethodSignature methodSignature = (MethodSignature) signature;
        // 字符串赋值
        String lockKey = CacheRedisKeyUtil.getLockWithRedisAopLockKeyRedisKey(CacheAopUtil.getCacheKey(proceedingJoinPoint));
        // 判断
        if (cacheService.lock(lockKey, expireSeconds)) {
            logger.info("%%%%%%LockWithCacheAop:aroundMethod:lockKey:" + lockKey + ":expireSeconds:" + expireSeconds + ":lock:success:description:" + description + "%%%%%%");
            // 尝试下面的代码
            try {
                // TODO
                Object object = proceedingJoinPoint.proceed();
                // 返回
                return object;
            // 捕捉异常
            } catch (Throwable e) {
                logger.info(e.getMessage(), e);
                // TODO
                throw e;
            // 最终执行
            } finally {
                logger.info("%%%%%%LockWithCacheAop:aroundMethod:lockKey:" + lockKey + ":expireSeconds:" + expireSeconds + ":unlock:success:description:" + description + "%%%%%%");
                // TODO
                cacheService.unlock(lockKey);
            }
        // 否则
        } else {
            // 判断是否是空
            if (description == null || description.equals("")) {
                // 赋值
                description = "";
            }
            // 抛出异常
            throw new CacheServerException(CacheServerErrorCode.LOCKWITHREDIS_LOCK_FAILED, description);
        }
    }

}
